<style lang="less">
.dragger{
    cursor: default;
}
</style>
<template>
    <div class="dragger" @click="onClick"><slot></slot></div>
</template>
<script>
import $ from 'jquery';
import lodash from 'lodash';

export default {
    props: {
        model: {
            type: Object,
            default() {
                return {};
            }
        },
        zoom: {
            type: Number,
            default: 1
        },
        getStartPosition: {
            type: Function,
            default() {
                const model = this.model || {};

                let x = model.left;
                if('x' in model) {
                    x = model.x;
                }

                let y = model.top;
                if('y' in model) {
                    y = model.y;
                }

                return {
                    x: isFinite(x) ? x : 0,
                    y: isFinite(y) ? y : 0
                };
            }
        }
    },
    data() {
        return {
            drag: {
                startX: 0,
                startY: 0,
                pageX: 0,
                pageY: 0,
                dx: 0,
                dy: 0
            }
        };
    },
    methods: {
        isDragable() {
            const model = this.model;
            const drag = this.drag;

            if(drag.draging || model.lock) {
                return false;
            }

            return true;
        },
        initDragger(element) {
            const self = this;
            const drag = this.drag;
            const doc = $(document);

            const handles = {
                init(e) {
                    e.stopPropagation();

                    const startPos = self.getStartPosition();

                    // props
                    lodash.assign(drag, {
                        draging: false,
                        model: self.model,
                        startX: startPos.x,
                        startY: startPos.y,
                        pageX: e.pageX,
                        pageY: e.pageY
                    });

                    doc.on('mousemove', handles.move);
                    doc.one('mouseup', handles.cancel);
                },
                move(e) {
                    e.preventDefault();

                    const zoom = self.zoom;

                    drag.dx = (e.pageX - drag.pageX) / zoom;
                    drag.dy = (e.pageY - drag.pageY) / zoom;

                    // 防止误触
                    let dOffsetMin = 3;
                    if(
                        !drag.draging && (
                            Math.abs(drag.dx) >= dOffsetMin ||
                            Math.abs(drag.dy) >= dOffsetMin
                        )
                    ) {
                        drag.draging = true;

                        self.$emit('active', drag, e);
                    }

                    if(drag.draging) {
                        self.$emit('moving', drag, e);
                    }
                },
                cancel(e) {
                    doc.off('mousemove', handles.move);

                    if(drag.draging) {
                        drag.draging = false;
                        drag.model = null;

                        self.$emit('inactive', drag, e);
                    }
                }
            };

            element.on('mousedown.dragger', handles.init);

            // clean
            this.$on('destroy', function() {
                element.off('.dragger');
            });
        },

        onClick(e) {
            this.$emit('click', this.model, e);
        }
    },

    created() {
        this.$nextTick(() => {
            let element = $(this.$el);
            if(!element.length) {
                return;
            }

            this.initDragger(element);
        });
    },

    beforeDestroy() {
        this.$emit('destroy');
    }
};
</script>
